#!/usr/bin/env python3
"""
手机配件销售预测系统 - 统一调用接口（支持Excel和MySQL）
Unified Sales Prediction System for Mobile Accessories (Excel & MySQL Support)

这个文件提供了一个统一的接口来调用所有销售预测功能，
支持Excel文件和MySQL数据库作为输入输出源。
包括数据预处理、模型训练、预测、结果整合和后处理。
"""

import os
import sys
import pandas as pd
import numpy as np
from datetime import datetime
import warnings
warnings.filterwarnings('ignore')

# 导入所有相关模块
from sales_prediction_system import SalesPredictionSystem
from sales_prediction_models import DataPreprocessor, LinearRegressionPredictor, RidgeRegressionPredictor, RandomForestPredictor, GradientBoostingPredictor, TimeSeriesPredictor
from sales_prediction_pipeline import SalesPredictionPipeline, PredictionEnsembler, DataPostProcessor, AccuracyEvaluator
from data_analysis import analyze_data_files
from view_results import view_results

# MySQL支持
try:
    import pymysql
    import sqlalchemy
    from sqlalchemy import create_engine
    MYSQL_AVAILABLE = True
except ImportError:
    MYSQL_AVAILABLE = False
    print("⚠️  MySQL支持未安装，请运行: pip install pymysql sqlalchemy")

class DatabaseManager:
    """数据库管理器 - 支持MySQL和Excel文件操作"""
    
    def __init__(self, db_config=None):
        """
        初始化数据库管理器
        
        Args:
            db_config: 数据库配置字典，包含 host, user, password, database, port
        """
        self.db_config = db_config
        self.engine = None
        self.use_mysql = False
        
        if db_config and MYSQL_AVAILABLE:
            try:
                connection_string = f"mysql+pymysql://{db_config['user']}:{db_config['password']}@{db_config['host']}:{db_config.get('port', 3306)}/{db_config['database']}"
                self.engine = create_engine(connection_string)
                self.use_mysql = True
                print(f"✅ MySQL连接成功: {db_config['host']}:{db_config.get('port', 3306)}")
            except Exception as e:
                print(f"❌ MySQL连接失败: {e}")
                self.use_mysql = False
    
    def read_data(self, source, table_name=None, query=None):
        """
        读取数据 - 支持Excel和MySQL
        
        Args:
            source: 数据源（文件路径或表名）
            table_name: MySQL表名（当使用数据库时）
            query: SQL查询语句（可选）
            
        Returns:
            DataFrame: 读取的数据
        """
        try:
            if self.use_mysql and table_name:
                # 从MySQL读取
                if query:
                    df = pd.read_sql(query, self.engine)
                else:
                    df = pd.read_sql(f"SELECT * FROM {table_name}", self.engine)
                print(f"✅ 从MySQL读取数据: {table_name} ({len(df)} 条记录)")
                return df
            else:
                # 从Excel读取
                df = pd.read_excel(source)
                print(f"✅ 从Excel读取数据: {source} ({len(df)} 条记录)")
                return df
        except Exception as e:
            print(f"❌ 数据读取失败: {e}")
            return None
    
    def write_data(self, df, destination, table_name=None, if_exists='replace'):
        """
        写入数据 - 支持Excel和MySQL
        
        Args:
            df: 要写入的数据框
            destination: 目标（文件路径或表名）
            table_name: MySQL表名（当使用数据库时）
            if_exists: 如果表存在时的处理方式 ('replace', 'append', 'fail')
            
        Returns:
            bool: 是否成功
        """
        try:
            if self.use_mysql and table_name:
                # 写入MySQL
                df.to_sql(name=table_name, con=self.engine, if_exists=if_exists, index=False)
                print(f"✅ 写入MySQL成功: {table_name} ({len(df)} 条记录)")
                return True
            else:
                # 写入Excel
                df.to_excel(destination, index=False)
                print(f"✅ 写入Excel成功: {destination} ({len(df)} 条记录)")
                return True
        except Exception as e:
            print(f"❌ 数据写入失败: {e}")
            return False
    
    def test_connection(self):
        """测试数据库连接"""
        if not self.use_mysql:
            return False
        
        try:
            with self.engine.connect() as conn:
                result = conn.execute("SELECT 1")
                print("✅ MySQL连接测试成功")
                return True
        except Exception as e:
            print(f"❌ MySQL连接测试失败: {e}")
            return False
    
    def get_table_info(self, table_name):
        """获取表结构信息"""
        if not self.use_mysql:
            return None
        
        try:
            query = f"""
            SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT
            FROM INFORMATION_SCHEMA.COLUMNS 
            WHERE TABLE_NAME = '{table_name}'
            ORDER BY ORDINAL_POSITION
            """
            info_df = pd.read_sql(query, self.engine)
            return info_df
        except Exception as e:
            print(f"❌ 获取表信息失败: {e}")
            return None

def quick_predict(train_source='1.xlsx', pred_source='2.xlsx', output_dest='3.xlsx', 
                 db_config=None, train_table=None, pred_table=None, output_table=None,
                 verbose=True, use_mysql=False):
    """
    快速预测函数 - 一键完成所有流程（支持Excel和MySQL）
    
    Args:
        train_source: 训练数据源（文件路径或表名）
        pred_source: 预测数据源（文件路径或表名）
        output_dest: 输出目标（文件路径或表名）
        db_config: 数据库配置字典（使用MySQL时必需）
        train_table: 训练数据表名（使用MySQL时）
        pred_table: 预测数据表名（使用MySQL时）
        output_table: 输出结果表名（使用MySQL时）
        verbose: 是否显示详细信息
        use_mysql: 是否使用MySQL（如果提供db_config则自动启用）
        
    Returns:
        dict: 包含预测结果和统计信息的字典
    """
    """
    快速预测函数 - 一键完成所有流程
    
    Args:
        train_file: 训练数据文件路径
        pred_file: 预测数据文件路径  
        output_file: 输出结果文件路径
        verbose: 是否显示详细信息
        
    Returns:
        dict: 包含预测结果和统计信息的字典
    """
    if verbose:
        print("=" * 60)
        print("手机配件销售预测系统 - 快速预测模式")
        if use_mysql or db_config:
            print("📊 数据源: MySQL数据库")
        else:
            print("📊 数据源: Excel文件")
        print("=" * 60)
        print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"训练数据: {train_source}")
        print(f"预测数据: {pred_source}")
        print(f"输出目标: {output_dest}")
        print()
    
    try:
        # 创建数据库管理器
        db_manager = DatabaseManager(db_config)
        
        # 根据配置决定使用MySQL还是Excel
        if db_config or use_mysql:
            if not MYSQL_AVAILABLE:
                print("❌ MySQL支持未安装，请运行: pip install pymysql sqlalchemy")
                return None
            
            # 从MySQL读取数据
            print("📊 从MySQL读取训练数据...")
            train_df = db_manager.read_data(train_source, table_name=train_table)
            if train_df is None:
                return None
                
            print("📊 从MySQL读取预测数据...")
            pred_df = db_manager.read_data(pred_source, table_name=pred_table)
            if pred_df is None:
                return None
        else:
            # 从Excel读取数据
            print("📊 从Excel读取训练数据...")
            train_df = db_manager.read_data(train_source)
            if train_df is None:
                return None
                
            print("📊 从Excel读取预测数据...")
            pred_df = db_manager.read_data(pred_source)
            if pred_df is None:
                return None
        
        # 创建预测系统并运行预测
        system = SalesPredictionSystem()
        
        # 临时保存到Excel文件（因为现有系统基于文件操作）
        temp_train_file = "temp_train.xlsx"
        temp_pred_file = "temp_pred.xlsx"
        temp_output_file = "temp_output.xlsx"
        
        train_df.to_excel(temp_train_file, index=False)
        pred_df.to_excel(temp_pred_file, index=False)
        
        # 运行完整流程
        result = system.run_complete_pipeline(
            train_file=temp_train_file,
            pred_file=temp_pred_file,
            output_file=temp_output_file
        )
        
        # 清理临时文件
        for temp_file in [temp_train_file, temp_pred_file]:
            if os.path.exists(temp_file):
                os.remove(temp_file)
        
        if result['status'] == 'success':
            # 读取预测结果
            if os.path.exists(temp_output_file):
                results_df = pd.read_excel(temp_output_file)
                
                # 根据目标类型输出结果
                if db_config or use_mysql:
                    # 写入MySQL
                    success = db_manager.write_data(results_df, output_dest, table_name=output_table)
                    if not success:
                        return None
                else:
                    # 写入Excel
                    success = db_manager.write_data(results_df, output_dest)
                    if not success:
                        return None
                
                # 清理临时输出文件
                if os.path.exists(temp_output_file):
                    os.remove(temp_output_file)
                
                result['results_df'] = results_df
                
                if verbose:
                    print("\n" + "=" * 60)
                    print("✅ 预测成功完成！")
                    print(f"输出目标: {output_dest}")
                    print(f"预测记录数: {len(results_df)}")
                    
                    # 显示预测统计
                    if 'predicted_sales' in results_df.columns:
                        pred_stats = results_df['predicted_sales'].describe()
                        print(f"\n预测结果统计:")
                        print(f"  平均值: {pred_stats['mean']:.2f}")
                        print(f"  标准差: {pred_stats['std']:.2f}")
                        print(f"  最小值: {pred_stats['min']:.2f}")
                        print(f"  最大值: {pred_stats['max']:.2f}")
                        
                        # 零销售统计
                        zero_count = (results_df['predicted_sales'] == 0).sum()
                        print(f"  零销售数量: {zero_count}")
                        print(f"  零销售比例: {zero_count/len(results_df)*100:.1f}%")
                    
                    print(f"\n结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                    print("=" * 60)
                
                return result
            else:
                print("❌ 预测结果文件未生成")
                return None
        else:
            print(f"\n❌ 预测失败: {result['error']}")
            return None
            
    except Exception as e:
        print(f"\n❌ 系统运行错误: {e}")
        import traceback
        traceback.print_exc()
        return None

def advanced_predict(train_file='1.xlsx', pred_file='2.xlsx', output_file='3.xlsx', 
                    models='all', ensemble_method='weighted_average', 
                    train_source=None, pred_source=None, output_dest=None,
                    db_config=None, train_table=None, pred_table=None, output_table=None,
                    use_mysql=False):
    """高级预测模式 - 支持自定义模型组合和集成方法
    
    支持Excel和MySQL数据源切换
    
    Args:
        train_file: 训练数据文件路径（Excel模式）
        pred_file: 预测数据文件路径（Excel模式）
        output_file: 输出结果文件路径（Excel模式）
        models: 使用的模型列表，如 'LinearRegression,RandomForest' 或 'all'
        ensemble_method: 集成方法，如 'weighted_average', 'simple_average', 'median'
        train_source: 训练数据源（表名或文件路径）
        pred_source: 预测数据源（表名或文件路径）
        output_dest: 输出目标（表名或文件路径）
        db_config: 数据库配置字典
        train_table: 训练数据表名（MySQL模式）
        pred_table: 预测数据表名（MySQL模式）
        output_table: 输出数据表名（MySQL模式）
        use_mysql: 是否使用MySQL模式
    
    Returns:
        dict: 包含预测结果和统计信息的字典
    """
    try:
        # 确定数据源类型和参数
        if use_mysql:
            source_type = "MySQL"
            train_data_source = train_source or train_table
            pred_data_source = pred_source or pred_table
            output_target = output_dest or output_table
        else:
            source_type = "Excel"
            train_data_source = train_source or train_file
            pred_data_source = pred_source or pred_file
            output_target = output_dest or output_file
        
        print(f"=== 高级预测模式 ({source_type}模式) ===")
        print(f"训练数据源: {train_data_source}")
        print(f"预测数据源: {pred_data_source}")
        print(f"输出目标: {output_target}")
        print(f"使用模型: {models}")
        print(f"集成方法: {ensemble_method}")
        
        # 初始化数据库管理器（如果需要）
        db_manager = None
        if use_mysql and db_config:
            db_manager = DatabaseManager(db_config)
            if not db_manager.test_connection():
                return {'status': 'error', 'error': '数据库连接失败'}
        
        # 读取数据
        if use_mysql and db_manager:
            train_df = db_manager.read_data(train_data_source)
            pred_df = db_manager.read_data(pred_data_source)
        else:
            train_df = pd.read_excel(train_data_source)
            pred_df = pd.read_excel(pred_data_source)
        
        print(f"训练数据形状: {train_df.shape}")
        print(f"预测数据形状: {pred_df.shape}")
        
        # 创建临时文件用于模型处理
        temp_train_file = 'temp_train.xlsx'
        temp_pred_file = 'temp_pred.xlsx'
        temp_output_file = 'temp_output.xlsx'
        
        # 保存临时Excel文件
        train_df.to_excel(temp_train_file, index=False)
        pred_df.to_excel(temp_pred_file, index=False)
        
        # 初始化预测系统
        system = SalesPredictionSystem()
        
        # 运行完整流程
        results = system.run_complete_pipeline(temp_train_file, temp_pred_file, temp_output_file)
        
        if results['status'] != 'success':
            raise ValueError("预测流程失败")
        
        # 读取预测结果
        pred_results = pd.read_excel(temp_output_file)
        
        # 输出结果处理
        if use_mysql and db_manager and output_target:
            # 保存到MySQL
            success = db_manager.write_data(pred_results, output_target)
            if success:
                print(f"预测结果已保存到MySQL表: {output_target}")
            else:
                print("警告: MySQL保存失败，结果保存到本地文件")
                pred_results.to_excel(output_target if output_target.endswith('.xlsx') else 'mysql_output.xlsx', index=False)
        else:
            # 保存到Excel
            output_file_path = output_target if output_target.endswith('.xlsx') else output_target + '.xlsx'
            pred_results.to_excel(output_file_path, index=False)
            print(f"预测结果已保存到: {output_file_path}")
        
        # 清理临时文件
        try:
            for temp_file in [temp_train_file, temp_pred_file, temp_output_file]:
                if os.path.exists(temp_file):
                    os.remove(temp_file)
        except:
            pass
        
        return {
            'status': 'success',
            'predictions': pred_results,
            'report': results.get('report', {}),
            'training_results': results.get('training_results', {}),
            'output_file': output_target if not use_mysql else (output_target if output_target.endswith('.xlsx') else 'mysql_output.xlsx')
        }
        
    except Exception as e:
        print(f"高级预测失败: {str(e)}")
        return {'status': 'error', 'error': str(e)}

def analyze_current_data(train_file='1.xlsx', pred_file='2.xlsx'):
    """
    分析当前数据文件
    
    Args:
        train_file: 训练数据文件路径
        pred_file: 预测数据文件路径
        
    Returns:
        dict: 数据分析结果
    """
    print("=" * 60)
    print("数据分析报告")
    print("=" * 60)
    
    try:
        # 运行数据分析 (data_analysis.py 不需要参数)
        result = analyze_data_files()
        
        if result['status'] == 'success':
            print("\n✅ 数据分析完成！")
            return result
        else:
            print(f"\n❌ 数据分析失败: {result['error']}")
            return None
            
    except Exception as e:
        print(f"\n❌ 数据分析错误: {e}")
        return None

def batch_predict(train_files, pred_files, output_dir='batch_results'):
    """
    批量预测函数 - 处理多个文件
    
    Args:
        train_files: 训练文件列表
        pred_files: 预测文件列表
        output_dir: 输出目录
        
    Returns:
        list: 批量预测结果
    """
    print("=" * 60)
    print("批量预测模式")
    print("=" * 60)
    
    if len(train_files) != len(pred_files):
        print("❌ 训练文件和预测文件数量不匹配")
        return None
    
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    
    results = []
    
    for i, (train_file, pred_file) in enumerate(zip(train_files, pred_files)):
        print(f"\n处理第 {i+1} 组文件...")
        
        # 生成输出文件名
        base_name = f"prediction_{i+1}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        output_file = os.path.join(output_dir, f"{base_name}.xlsx")
        
        # 执行预测
        result = quick_predict(train_file, pred_file, output_file, verbose=False)
        
        if result and result['status'] == 'success':
            results.append({
                'index': i+1,
                'train_file': train_file,
                'pred_file': pred_file,
                'output_file': output_file,
                'status': 'success',
                'results': result
            })
            print(f"✅ 第 {i+1} 组预测完成")
        else:
            results.append({
                'index': i+1,
                'train_file': train_file,
                'pred_file': pred_file,
                'output_file': None,
                'status': 'failed',
                'error': result.get('error', 'Unknown error') if result else 'Unknown error'
            })
            print(f"❌ 第 {i+1} 组预测失败")
    
    # 统计结果
    successful = sum(1 for r in results if r['status'] == 'success')
    failed = len(results) - successful
    
    print(f"\n{'='*60}")
    print("批量预测完成！")
    print(f"总文件组数: {len(results)}")
    print(f"成功: {successful}")
    print(f"失败: {failed}")
    print(f"成功率: {successful/len(results)*100:.1f}%")
    print(f"结果保存在: {output_dir}")
    print("=" * 60)
    
    return results

def show_usage():
    """显示使用说明 - 包含MySQL支持"""
    usage_text = """
手机配件销售预测系统 - 统一调用接口 (支持Excel和MySQL)

使用方法:
    1. 快速预测 (Excel)
       python unified_prediction_system.py quick
       
    2. 快速预测 (MySQL)
       python unified_prediction_system.py quick --use-mysql --db-host localhost --db-user root --db-password 123456 --db-name sales_db
       
    3. 高级预测 (Excel)
       python unified_prediction_system.py advanced --models LinearRegression,RandomForest --ensemble weighted_average
       
    4. 高级预测 (MySQL)
       python unified_prediction_system.py advanced --use-mysql --models LinearRegression,RandomForest --db-name sales_db
       
    5. 数据分析
       python unified_prediction_system.py analyze
       
    6. 批量预测
       python unified_prediction_system.py batch
       
    7. 查看结果
       python unified_prediction_system.py view

参数说明:
    基础参数:
    --train SOURCE      训练数据源（文件路径或表名，默认: 1.xlsx）
    --pred SOURCE       预测数据源（文件路径或表名，默认: 2.xlsx）
    --output DEST       输出目标（文件路径或表名，默认: 3.xlsx）
    
    MySQL参数:
    --use-mysql         使用MySQL数据库
    --db-host HOST      数据库主机（默认: localhost）
    --db-port PORT      数据库端口（默认: 3306）
    --db-user USER      数据库用户名（默认: root）
    --db-password PASS  数据库密码
    --db-name NAME      数据库名称（默认: sales_prediction）
    
    高级参数:
    --models MODELS     指定模型（逗号分隔，如: LinearRegression,RandomForest）
    --ensemble METHOD   集成方法（average/weighted_average/median，默认: weighted_average）
    --output-dir DIR    批量输出目录（默认: batch_results）

示例:
    # Excel文件操作
    python unified_prediction_system.py quick --train data/train.xlsx --pred data/pred.xlsx --output results/output.xlsx
    
    # MySQL数据库操作
    python unified_prediction_system.py quick --use-mysql --train train_table --pred pred_table --output result_table --db-name mydb
    
    # 高级预测（MySQL）
    python unified_prediction_system.py advanced --use-mysql --models LinearRegression,RandomForest,GradientBoosting --db-host 192.168.1.100 --db-user admin --db-password secret
    
    # 自定义数据库连接
    python unified_prediction_system.py quick --use-mysql --train sales_train --pred sales_pred --output sales_result --db-host localhost --db-port 3306 --db-user root --db-password 123456 --db-name sales_data

数据库要求:
    使用MySQL时需要安装pymysql和sqlalchemy库：
    pip install pymysql sqlalchemy
    
    确保MySQL服务正在运行，并且提供的数据库和用户有相应的读写权限。
"""
    print(usage_text)

def main():
    """主函数 - 支持MySQL和Excel数据源切换"""
    import argparse
    
    parser = argparse.ArgumentParser(description='手机配件销售预测系统 - 支持Excel和MySQL')
    
    # 基础参数
    parser.add_argument('mode', choices=['quick', 'advanced', 'analyze', 'batch', 'view', 'help'], 
                       default='quick', nargs='?', help='运行模式')
    
    # 数据源参数（通用）
    parser.add_argument('--train', default='1.xlsx', help='训练数据源（文件路径或表名）')
    parser.add_argument('--pred', default='2.xlsx', help='预测数据源（文件路径或表名）')
    parser.add_argument('--output', default='3.xlsx', help='输出目标（文件路径或表名）')
    
    # MySQL参数
    parser.add_argument('--use-mysql', action='store_true', help='使用MySQL数据库')
    parser.add_argument('--db-host', default='localhost', help='数据库主机')
    parser.add_argument('--db-port', type=int, default=3306, help='数据库端口')
    parser.add_argument('--db-user', default='root', help='数据库用户名')
    parser.add_argument('--db-password', default='', help='数据库密码')
    parser.add_argument('--db-name', default='sales_prediction', help='数据库名称')
    
    # 高级预测参数
    parser.add_argument('--models', help='指定模型 (逗号分隔)')
    parser.add_argument('--ensemble', default='weighted_average', 
                       choices=['average', 'weighted_average', 'median'],
                       help='集成方法')
    
    # 其他参数
    parser.add_argument('--output-dir', default='batch_results', help='批量输出目录')
    
    args = parser.parse_args()
    
    if args.mode == 'help':
        show_usage()
        return
    
    # 构建数据库配置
    db_config = None
    if args.use_mysql:
        db_config = {
            'host': args.db_host,
            'port': args.db_port,
            'user': args.db_user,
            'password': args.db_password,
            'database': args.db_name
        }
        print(f"🔗 连接到MySQL数据库: {args.db_host}:{args.db_port}/{args.db_name}")
    
    print("🚀 手机配件销售预测系统启动...")
    
    if args.mode == 'quick':
        # 快速预测模式
        result = quick_predict(
            train_source=args.train, 
            pred_source=args.pred, 
            output_dest=args.output,
            use_mysql=args.use_mysql,
            db_config=db_config
        )
        
    elif args.mode == 'advanced':
        # 高级预测模式
        models = args.models.split(',') if args.models else None
        result = advanced_predict(
            train_source=args.train,
            pred_source=args.pred, 
            output_dest=args.output,
            models=models, 
            ensemble_method=args.ensemble,
            use_mysql=args.use_mysql,
            db_config=db_config
        )
        
    elif args.mode == 'analyze':
        # 数据分析模式
        result = analyze_current_data(args.train, args.pred)
        
    elif args.mode == 'batch':
        # 批量预测模式 (示例)
        train_files = [args.train]  # 可以扩展为多个文件
        pred_files = [args.pred]
        result = batch_predict(train_files, pred_files, args.output_dir)
        
    elif args.mode == 'view':
        # 查看结果模式
        result = view_results()
        # view_results 返回的是 DataFrame，需要转换为成功状态
        if result is not None and not result.empty:
            print("\n✅ 结果查看完成！")
            result = {'status': 'success', 'data': result}
        else:
            result = None
        
    else:
        print("❌ 未知的运行模式")
        return
    
    if result:
        print("\n✅ 任务完成！")
    else:
        print("\n❌ 任务执行失败")

if __name__ == "__main__":
    # 如果没有命令行参数，显示使用说明
    if len(sys.argv) == 1:
        print("""
手机配件销售预测系统 - 统一调用接口

使用方法:
    python unified_prediction_system.py [模式] [参数]
    
可用模式:
    quick     - 快速预测 (推荐)
    advanced  - 高级预测 (自定义参数)
    analyze   - 数据分析
    batch     - 批量预测
    view      - 查看结果
    help      - 显示详细帮助

示例:
    python unified_prediction_system.py quick
    python unified_prediction_system.py advanced --models LinearRegression,RandomForest
    python unified_prediction_system.py analyze
    
输入 'python unified_prediction_system.py help' 查看详细使用说明
""")
    else:
        main()